package com.qjc.demo.thread.threadlocal;

/**
 * @Description:
 * @Author: qjc
 * @Date: 2020/7/17
 */
public class InheritableThreadLocalDemo {

    /*那么在什么情况下需要 线程可以获取父线程的 threadlocal 变量呢？情况还是蛮多
    的，比如子线程需要使用存放在 threadlocal 中的用户 登录信息，再比如一些中间件
    要把统一的 id 个调用链路记录下来。其实子线程使用父线程中的 threadlocal
    法有多种方式， 比如创建线程时传入父线程中的变量，并将其复制到子线程中，或者在父
    线程中构造一个 map 作为参数传递给子线程，但是这些都改变了我们的使用习惯，所以
    在这些情况下 Inheritable ThreadLocal 就显得比较有用*/

    //ThreadLocal不可继承，也就是说在主线程中设置值，在子线程中是获取不到的
    static ThreadLocal<String> threadLocal = new ThreadLocal<>();
    //InheritableThreadLocal可继承，也就是说在主线程中设置值，在子线程中是能获取到的
    static ThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>();

    public static void main(String[] args) {
        try {
            // ThreadLocal在主线程中设置值
            threadLocal.set("hello main thread");
            // 在子线程中获取值是获取不到的
            Thread threadSon1 = new Thread(() -> System.out.println("son Thread:" + threadLocal.get()));
            threadSon1.start();
            // 只有在主线程中获取值才能获取到
            System.out.println("main Thread:" + threadLocal.get());
        } finally {
            /**
             * 必须回收自定义的ThreadLocal变量，尤其在线程池场景下，线程经常会被复用，
             * 如果不清理自定义的 ThreadLocal变量，可能会影响后续业务逻辑和造成内存泄露等问题。
             * 尽量在代理中使用try-finally块进行回收。
             */
            threadLocal.remove();
        }

        try {
            // InheritableThreadLocal在主线程中设置值
            inheritableThreadLocal.set("hello main thread");
            // 在子线程中获取值是能获取到的，因为InheritableThreadLocal是可继承的
            Thread threadSon2 = new Thread(() -> System.out.println("son Thread:" + inheritableThreadLocal.get()));
            threadSon2.start();
            // 在主线程中获取值也是可以获取到的
            System.out.println("main Thread:" + inheritableThreadLocal.get());
        } finally {
            inheritableThreadLocal.remove();
        }
    }

}
